//
// Created on 2023/5/29.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef VIDEO_ENCODER_NAPI_H_
#define VIDEO_ENCODER_NAPI_H_


#include <js_native_api.h>
#include <js_native_api_types.h>
#include <memory>
#include "avcodec_callback_napi.h"
#include "video_encoder.h"
#include "uv.h"


namespace OHOS {
namespace Media {
struct VideoEncoderCommonArgs;
struct VideoEncoderAsyncContext;
using Context = VideoEncoderAsyncContext*;
using CompleteCallback = void (*)(napi_env env, napi_status status, Context context);

#define LOG_TAG VideoEncoderNapi




class VideoEncoderNapi {
  public:
    static napi_value Init(napi_env env, napi_value exports);
    static void DoCallBack(std::shared_ptr<VideoEncoderAsyncContext> context,
                               std::string name,
                               CompleteCallback callBack);
  private:
    static napi_value Constructor(napi_env env, napi_callback_info info);
    static void Destructor(napi_env env, void *nativeObject, void *finalize);
    static napi_value CreateVideoEncoder(napi_env env, napi_callback_info info);
    static napi_value SetCallback(napi_env env, napi_callback_info info);
    static napi_value Configure(napi_env env, napi_callback_info info);
    static napi_value Prepare(napi_env env, napi_callback_info info);
    static napi_value Start(napi_env env, napi_callback_info info);
    static napi_value Stop(napi_env env, napi_callback_info info);
    static napi_value Flush(napi_env env, napi_callback_info info);
    static napi_value Reset(napi_env env, napi_callback_info info);
    static napi_value GetOutputDescription(napi_env env, napi_callback_info info);
    static napi_value Release(napi_env env, napi_callback_info info);
    static napi_value SendFrameData(napi_env env, napi_callback_info info);
    static napi_value On(napi_env env, napi_callback_info info);
    static napi_value JsOn(napi_env env, napi_callback_info info);
    static void getVideoEncoderNapi(napi_env env, napi_value thisVar, VideoEncoderNapi **result);
    static AvFormat getAvFormat(napi_env env, napi_value value);
    void OnOutputBufferAvailable(uint8_t* data,int32_t size,int32_t pts,uint32_t flags);
    static napi_value JSCommonProcess(VideoEncoderCommonArgs &args);
    VideoEncoderNapi();
    ~VideoEncoderNapi();
    static thread_local napi_ref constructor_;
    napi_env env_ = nullptr;
    std::shared_ptr<VEncDemo> encoder_ = nullptr;
    std::shared_ptr<VideoEncoder> videoEncoder = nullptr;
    std::shared_ptr<AvCodecCallbackNapi> codecCallback = nullptr;
};

struct VideoEncoderAsyncContext {
    napi_env env = nullptr;
    napi_async_work work = nullptr;
    napi_deferred deferred = nullptr;
    napi_ref callbackRef = nullptr;
    VideoEncoderNapi *constructor_ = nullptr;
    std::shared_ptr<VideoEncoder> encoder_ = nullptr;
    uint32_t status;
};
struct VideoEncoderInnerContext {
    napi_status status;
    napi_value result = nullptr;
    napi_value thisVar = nullptr;
    size_t argc;
    std::vector<napi_value> argv;
    std::string onType;
    int32_t refCount = 1;
    std::unique_ptr<VideoEncoderAsyncContext> context = nullptr;
};

using CommonFunc = bool (*)(VideoEncoderCommonArgs &args, VideoEncoderInnerContext &ic);
using CompleteCallback = void (*)(napi_env env, napi_status status, Context context);
enum class CallType : uint32_t {
    STATIC = 0,
    GETTER = 1,
    ASYNC = 2,
};

struct VideoEncoderCommonArgs {
    napi_env env;
    napi_callback_info info;
    CallType async;
    const std::string name;
    CompleteCallback callBack;
    size_t argc;
    CommonFunc queryArgs;
    CommonFunc nonAsyncBack;
    bool asyncLater = false;
};

class VideoEncoderAvaliableListener : public AVCodecCallback {
public:
    ~VideoEncoderAvaliableListener()
    {
        context = nullptr;
        callBack = nullptr;
    }
    void OnOutputBufferAvailable(uint8_t* data,int32_t size,int32_t pts,uint32_t flags) override
    {
        VideoEncoderNapi::DoCallBack(context, name, callBack);
    }
    void OnCodecError(int32_t errorCode)override{
    
    }
    void OnOutputFormatChanged(AvFormat* format)override{
    
    }
    void OnInputBufferAvailable(uint8_t* data, int32_t size) override{
    
    }
    std::shared_ptr<VideoEncoderAsyncContext> context = nullptr;
    std::string name;
    CompleteCallback callBack = nullptr;
};

} // namespace Media
} // namespace OHOS

#endif //VIDEO_ENCODER_NAPI_H_
